﻿package src.computation {
	
	/**
	* 
	* Reliability project
	* -----------------------
	* @author  Dmitrij Boycov
	* @mail    dmitry.boycov@gmail.com
	* @date    April 27, 2010
	* @version 1
	* 
	*/
	
	import fl.data.DataProvider;
	import flash.utils.Dictionary;
	// src
	import src.util.Utils;
	
	public class Stock{
		
		private var startID = 1;
		
		/**
		 * Each item of dictionary following fields
		 * 		type - element type 
		 *		numberOnTime - is dictionary, when key is time value is number of reserve elements.
		 *		desc - description 
		 *		law - distribution law
		 *		recovery - recovery parametrs
		 *		stockId - id in stock
		 * key is sockId
		 */
		private var data;
		/**
		 *  It is nedd for compute recovery
		 */
		private var timeSystemWork;
		
		public function Stock(data) {
			this.data = new Dictionary(true);
			if(data !=null){
				for (var i = 0; i < data.length; i++ ) {
					var obj = data.getItemAt(i);
					if (obj!=null && obj.stockId != null) {
						var numberOnTime = new Dictionary();						
						numberOnTime[0] = new Number(obj.number);
						var newObj = { type: obj.type,
									   desc: obj.desc,
									   law: obj.law,
									   recovery: obj.recovery,
									   stockId: obj.stockId,
									   numberOnTime:numberOnTime
						}
						this.data[obj.stockId] = newObj;
					}
				}
			}			 
		}
		
		public function setTimeSystemWork(t) {
			this.timeSystemWork = t;
		}
		
		/**
		 * getItemAt
		 * @param	id - stock id
		 */
		public function getItemAt(id) {			
			return this.data[id];
		}
		
		public function haveReserveElements(id,time):Boolean {
			if ( id == null) return false;
			var obj = this.data[id];
			if (obj != null && obj.numberOnTime != null) {				
				var tleft:Number = 0;
				var stleft = 0;
				for (var st in obj.numberOnTime ) {
					var t:Number = new Number(st);
					if (t > tleft && t <= time) {
						tleft = t;
						stleft = st;
					}
				}
	//			trace("----have------");
	//			trace("time:" + time);
	//			trace("t:" + stleft);
	//			trace("n:" + obj.numberOnTime[stleft]);
				if (obj.numberOnTime[stleft] > 0){					
					return true;
				}else{
					return false;
				}
			}
			return false;
		}
		
		private function recalculationOfNotRecoveredElements(el, time, tleft, tright) {		
			time = this.norm(time);	
			if ( el.numberOnTime[time] == null) {
				if(el.numberOnTime[tleft]>0){
					el.numberOnTime[time] = el.numberOnTime[tleft];
				}else {
					el.numberOnTime[time] = 0; 
				}
			}
			for (var t in el.numberOnTime ) {
				if (t >= time) {
					if(el.numberOnTime[t]>0){
						el.numberOnTime[t]--;
					}
				}
			}			
		}
		
		private function norm(t):Number {
			return Math.round(t * Math.pow(10, 12)) / Math.pow(10, 12);
		}
		
		private function recalculationOfRecoveredElements(el, time:Number, tleft:Number, tright:Number, recoveryTime:Number) {
			time = this.norm(time);			
			var stime:String =  new String(time)
			var stleft:String = new String(tleft);
			var stright:String = new String(tright);
			var srecoveryTime = new String(recoveryTime);
			if ( el.numberOnTime[stime] == null) {				
				if(el.numberOnTime[stleft]>0){
					el.numberOnTime[stime] = el.numberOnTime[stleft] - 1;
				}else {					
					el.numberOnTime[stime] = 0; 
				}
			}else{ if(el.numberOnTime[stime]>0){
				el.numberOnTime[stime] = el.numberOnTime[stime] - 1;
				}
			}			
			var end:Number = time + recoveryTime;
			end = this.norm(end);
			var send = new String(end);	
			if (end == tright) return;
			if (end < tright || tright == 0) {
				if (el.numberOnTime[tleft] > 0) {
					el.numberOnTime[end] = el.numberOnTime[tleft];
				}else {
					el.numberOnTime[send] = 0;
				}	
				return;
			}
			if (end > tright) {
				if (el.numberOnTime[end] == null) {
					var tendLeft:Number = tright;
					var stendLeft:String = stright;
					for (var st:String in el.numberOnTime) {
						var t = new Number(st);
						if (t < end && t > tendLeft ) {
							tendLeft = t;
							stendLeft = st;
						}
					}
					el.numberOnTime[end] = el.numberOnTime[stendLeft];
				}
				var keys = Utils.dictKeys(el.numberOnTime);
				for (var i= 0; i < keys.length; i++ ) {				
					var t = new Number(keys[i]);
					if ( (t > time) && (t < end)){
						if(el.numberOnTime[keys[i]]>0){						
							el.numberOnTime[keys[i]]--;
						}
					}	
				}
			}
		}
		
		public function elementToRepair(id,time:Number) {
			var el = this.data[id];
			if (el != null && el.numberOnTime != null) {
				var tleft:Number = 0; 
				var tright:Number = 0;
				// find left time and right time from time
				for (var st:String in el.numberOnTime) {
					var t:Number = new Number(st);
					if ((t <= time) && (t > tleft)){ tleft = t};
					if (t > time && (tright > t || tright == 0)){ tright = t};
				}
				if (el.recovery == null) {
					this.recalculationOfNotRecoveredElements(el, time,tleft,tright);
				}
				el.recovery.setSystemWorkTime(timeSystemWork);
				var recoveryTime:Number = el.recovery.getTime();
				if (recoveryTime < 0) {
					this.recalculationOfNotRecoveredElements(el, time,tleft,tright);
				}else {
					this.recalculationOfRecoveredElements(el, time,tleft,tright,recoveryTime)
				}				
			}
		}
		
		public function print() { 
			for each(var obj in this.data) {
				if (obj.numberOnTime != null) {					
					var keys = Utils.dictKeys(obj.numberOnTime);					
					keys.sort(Array.NUMERIC);
					var str = obj.type + ":";					
					for (var i= 0; i < keys.length; i++ ) {
						str += "t(" + keys[i] + ")=" + obj.numberOnTime[keys[i]] + "   ";
					}
					trace(str);
				}
			}
		}
	}	
}